This page last changed on Jun 18, 2004 by plightbo.

综述

在许多应用中, 都有一些对象必需使用组件对象. 简单来说, IoC模式允许父对象(在Webwork和XWork中是ComponentManager实例)向需要的活动对象提供资源对象(通常是一个活动, 但也可以是任何实现适当的enabler接口的对象), 而不是需要对象自己获取资源.

有两种方式实现IoC: 初始化或使用enabler接口. 使用初始化方式, 给定活动对象使用资源对象作为构造函数的参数完成初始化. 使用enabler接口, 活动将具有接口的方法"setComponent(ComponentObject r);", 该方法允许在活动对象初始化后将资源对象传递到该对象. 根据对象实现的接口传递对应的组件对象. XWork使用enablers传递组件.

为什么使用IoC?

那么IoC为什么有用呢? 这意味着我们可以采用自顶向下方式开发组件(通常是某类服务[, 如JDBC连接, 在客户程序中不需要知道连接是Oracle的还是Sybase的, 也不需要知道连接是从连接池获取还是其他方式]), 而不需要构建一个注册类让客户调用它以获取组件实例.

实现服务的传统方式可能采用下面类似的步骤:
  1. 编写组件(如ExchangeRateService)
  2. 编写客户类(如XWork活动)
  3. 编写保存该组件的注册类(如Registry)
  4. 编写在注册类中注册指定组件对象的代码 (如Registry.registerService(new MyExchangeRateService()))
  5. 在客户类中使用注册类获取服务(如, ExchangeRateService ers = Registry.getExchangeRateService())
  6. 在客户类中调用组件对象(如, String baseCurrencyCode = ers.getBaseCurrency())

使用IoC, 该过程简化为:
  1. 编写组件类(如ExchangeRateService)
  2. 在XWork中注册组件类(如, componentManager.addEnabler(MyExchangeRateService, ExchangeRateAware))
  3. 编写客户类, 并确保实现了enabler接口(如一个实现了ExchangeRateAware接口的XWork活动)
  4. 在客户类中直接访问组件实例(如, String baseCurencyCode = ers.getBaseCurrency())

反转控制的更多优点如下:
  1. 可测试能力 - 更容易进行测试: 使用enabler方法向对象传递mock对象, 而不需要创建对象用于获取组件的容器.
  2. 组件自描述. 当需要初始化一个组件时, 可以很容易得得知该组件需要那些依赖对象(组件)而不需要查看源代码, 文档或示例.
  3. 使用反射(reflection)很容易发现依赖关系. 从图表生成到运行时优化都会带来好处(例如, 可以提前判断满足请求所需的组件并可以异步进行组件准备).
  4. 避免使用超大工厂(super-uber-mega-factory)设计模式(应用的全部组件都保存在一个类中, 这直接导致与某些类的紧密绑定而难于'just use that one class').
  5. 符合Demeter定律(Law of Demeter). 有人认为这很愚蠢, 但在实践中我发现这样工作的更好. 每个类仅和真正使用它的类耦合(and it should never use too much). 这种方法鼓励每个类承担更少的责任, 从而产生更清晰的设计.
  6. 允许与环境(context)隔离并可以绕过. ThreadLocal在web应用中可能很合适[hibernate样例代码中使用TnreafLocal管理session对象, 本文可能是针对这一情况], 但并不一定适合高并发的同步应用(如消息驱动的应用).
Document generated by Confluence on Dec 14, 2004 16:36